home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 2: Applications
/
Linux Cubed Series 2 - Applications.iso
/
circuits
/
pcb-1.000
/
pcb-1
/
pcb-1.3
/
find.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-01
|
40KB
|
1,388 lines
/*
* COPYRIGHT
*
* PCB, interactive printed circuit board design
* Copyright (C) 1994,1995 Thomas Nau
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contact addresses for paper mail and Email:
* Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
* Thomas.Nau@rz.uni-ulm.de
*
*/
static char *rcsid = "$Header: /sda4/users/nau/src/pcb/RCS/find.c,v 2.1 1994/09/28 14:26:11 nau Exp nau $";
/*
* short description:
* - all pin and via pointers are copied to a single array to have linear
* access to them. All pointers refer to this list.
* - two fields, with pointers to line data, are build for each layer
* sorted by:
* - the lower x line coordinates in decending order and
* - the higher x line coordinates in asscending order.
* They are used to have fewer accesses when looking for line connections.
* - lists for pins and vias, for lines and for polygons are created.
* Every object that has to be checked is added to its list.
* - there's no 'speed-up' mechanism for polygons because they are not used
* as often as lines and are much easier to handle
* - the maximum distance between line and pin ... would depend on the angle
* between them. To speed up computation the limit is set to one third
* of the thickness of the objects which is close to
* thickness/2/sqrt(2). The result is that connections between objects
* with a distance close to that limit are not recognized.
*
* PV: means pin or via (objects that connect layers)
* LO: all non PV objects (layer related objects like lines)
*
* 1. first, the PV at the given coordinates is looked up
* 2. all LO connections to that PV are looked up next
* 3. lookup of all LOs connected to LOs from (2).
* This step is repeated until no more new connections are found.
* 4. lookup all PVs connected to the LOs from (2) and (3)
* 5. start again with (1) for all new PVs from (4)
*
* Intersection of line <--> circle:
* - calculate the signed distance from the line to the center,
* return false if abs(distance) > R
* - get the distance from the line <--> distancevector intersection to
* (X1,Y1) in range [0,1], return true if 0 <= distance <= 1
* - depending on (r > 1.0 or r < 0.0) check the distance of X2,Y2 or X1,Y1
* to X,Y
* - There is a maximum difference between the inner circle
* of a PV and the outer one of 8.2% of its radius.
* This difference is ignored which means that lines that end
* right at the corner of a PV are not recognized.
*
* Intersection of line <--> line:
* - see the description of 'LineLineIntersect()'
*/
/* routines to find connections between pins, vias, lines...
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sys/times.h>
#include "global.h"
#include "data.h"
#include "dialog.h"
#include "draw.h"
#include "find.h"
#include "mymem.h"
#include "misc.h"
#include "search.h"
#include "set.h"
/* ----------------------------------------------------------------------
* some math constants
*/
#ifndef M_SQRT1_2 /* 1/sqrt(2) */
#define M_SQRT1_2 0.70710678118654752440
#endif
/* ---------------------------------------------------------------------------
* some local macros
*/
#define SEPERATE(FP) \
{ \
int i; \
for (i = Settings.CharPerLine; i; i--) \
fputc('=', (FP)); \
fputc('\n', (FP)); \
}
#define LINELIST_ENTRY(L,I) \
(((LineTypePtr *)LineList[(L)].Data)[(I)])
#define POLYGONLIST_ENTRY(L,I) \
(((PolygonTypePtr *)PolygonList[(L)].Data)[(I)])
#define PVLIST_ENTRY(I) \
(((PVDataTypePtr *)PVList.Data)[(I)])
#define IS_PV_ON_LINE(PV,Line) \
(IsPointOnLine((PV)->X,(PV)->Y,(PV)->Thickness/2+1,(Line)))
#define ADD_PV_TO_LIST(Ptr) \
{ \
SET_FLAG(FOUNDFLAG, (Ptr)->Data); \
PVLIST_ENTRY(PVList.Number) = (Ptr); \
PVList.Number++; \
}
#define ADD_LINE_TO_LIST(L,Ptr) \
{ \
SET_FLAG(FOUNDFLAG, (Ptr)); \
LINELIST_ENTRY((L),LineList[(L)].Number) = (Ptr); \
LineList[(L)].Number++; \
}
#define ADD_POLYGON_TO_LIST(L,Ptr) \
{ \
SET_FLAG(FOUNDFLAG, (Ptr)); \
POLYGONLIST_ENTRY((L), PolygonList[(L)].Number) = (Ptr);\
PolygonList[(L)].Number++; \
}
/* ---------------------------------------------------------------------------
* some local types
*/
typedef struct
{
void **Data; /* pointer to index data */
Cardinal Position, /* currently used position */
DrawPosition,
Number; /* number of objects in list */
} ListType, *ListTypePtr;
typedef struct /* holds a copy of all pins and vias */
{ /* plus a pointer to the according element */
PinTypePtr Data;
ElementTypePtr Element;
} PVDataType, *PVDataTypePtr;
/* ---------------------------------------------------------------------------
* some local identifiers
*/
static Widget Popup; /* abort dialog and flag */
static Boolean Abort;
static LineTypePtr *LineSortedByLowX[MAX_LAYER], /* sorted array of */
*LineSortedByHighX[MAX_LAYER]; /* line pointers */
static PVDataTypePtr PVSortedByX; /* same for PV */
static Cardinal TotalPV; /* total number of PV */
static ListType LineList[MAX_LAYER], /* list of objects to */
PolygonList[MAX_LAYER],
PVList;
/* ---------------------------------------------------------------------------
* some local prototypes
*/
static void CB_Abort(Widget, XtPointer, XtPointer);
static void CreateAbortDialog(void);
static Boolean CheckAbort(void);
static int CompareLineByLowX(const void *, const void *);
static int CompareLineByHighX(const void *, const void *);
static int ComparePVByX(const void *, const void *);
static Cardinal GetLineByLowX(Position, Cardinal);
static Cardinal GetLineByHighX(Position, Cardinal);
static Cardinal GetPVByX(Position);
static void FreeConnectionLookupMemory(void);
static void InitConnectionLookup(void);
static LineTypePtr *GetIndexOfLines(Position, Position, Cardinal, Cardinal *);
static PVDataType *LookupPVByCoordinates(Position, Position);
static void LookupLOConnectionsToPVList(void);
static void LookupLOConnectionsToLOList(void);
static void LookupPVConnectionsToLOList(void);
static void LookupLOConnectionsToLine(LineTypePtr, Cardinal);
static void LookupLOConnectionsToPolygon(PolygonTypePtr, Cardinal);
static Boolean IsLineInPolygon(LineTypePtr, PolygonTypePtr);
static Boolean IsPolygonInPolygon(PolygonTypePtr, PolygonTypePtr);
static Boolean PrintElementConnections(ElementTypePtr, FILE *);
static Boolean LineLineIntersect(LineTypePtr, LineTypePtr);
static Boolean ListsEmpty(void);
static void DoIt(void);
static void PrintPinConnections(FILE *);
static Boolean PrintAndSelectUnusedPinsOfElement(ElementTypePtr, FILE *);
static void DrawNewConnections(void);
static void ResetConnections(void);
/* ---------------------------------------------------------------------------
* callback for 'AbortDialog' dialog
*/
static void CB_Abort(Widget W, XtPointer ClientData, XtPointer CallData)
{
Abort = True;
}
/* ---------------------------------------------------------------------------
* creates an 'Abort' dialog
*/
static void CreateAbortDialog()
{
static DialogButtonType buttons[] = {
{ "defaultButton", " Abort ", CB_Abort, (XtPointer) NULL, NULL }};
/* create dialog box */
Popup = CreateDialogBox("press button to abort 'scanning of connections'",
buttons, ENTRIES(buttons));
Abort = False;
StartDialog(Popup);
}
/* ---------------------------------------------------------------------------
* dispatches all events and returns the status of
* 'Abort'
*/
static Boolean CheckAbort(void)
{
XEvent event;
while (XtAppPending(Context))
{
XtAppNextEvent(Context, &event);
XtDispatchEvent(&event);
}
return(Abort);
}
/* ---------------------------------------------------------------------------
* quicksort compare function for line coordinate X1
* line field is sorted in decending order of X1
*/
static int CompareLineByLowX(const void * Index1, const void * Index2)
{
LineTypePtr ptr1 = *((LineTypePtr *) Index1),
ptr2 = *((LineTypePtr *) Index2);
return((int) (MIN(ptr2->X1, ptr2->X2) -MIN(ptr1->X1, ptr1->X2)));
}
/* ---------------------------------------------------------------------------
* quicksort compare function for line coordinate X2
* line field is sorted in ascending order of X2
*/
static int CompareLineByHighX(const void * Index1, const void * Index2)
{
LineTypePtr ptr1 = *((LineTypePtr *) Index1),
ptr2 = *((LineTypePtr *) Index2);
return((int) (MAX(ptr1->X1, ptr1->X2) -MAX(ptr2->X1, ptr2->X2)));
}
/* ---------------------------------------------------------------------------
* quicksort compare function for pin (via) coordinate X
* for sorting the PV field in ascending order of X
*/
static int ComparePVByX(const void * Index1, const void * Index2)
{
PinTypePtr ptr1 = ((PVDataTypePtr) Index1)->Data,
ptr2 = ((PVDataTypePtr) Index2)->Data;
return((int) (ptr1->X -ptr2->X));
}
/* ---------------------------------------------------------------------------
* returns a the maximum index which matches
* X1(line[index]) >= X for all index <= 'found one'
* the field is sorted in a descending order
*/
static Cardinal GetLineByLowX(Position X, Cardinal Layer)
{
LineTypePtr *ptr = LineSortedByLowX[Layer];
int left = 0,
right = PCB->Data->Layer[Layer].LineN -1,
position;
while (left < right)
{
position = (left +right) /2;
if (MIN(ptr[position]->X1, ptr[position]->X2) <= X)
right = position;
else
left = position+1;
}
return((Cardinal) left);
}
/* ---------------------------------------------------------------------------
* returns a the maximum index which matches
* X2(line[index]) <= X for all index <= 'found one'
* the field is sorted in a ascending order
*/
static Cardinal GetLineByHighX(Position X, Cardinal Layer)
{
LineTypePtr *ptr = LineSortedByHighX[Layer];
int left = 0,
right = PCB->Data->Layer[Layer].LineN -1,
position;
while (left < right)
{
position = (left +right) /2;
if (MAX(ptr[position]->X1, ptr[position]->X2) >= X)
right = position;
else
left = position+1;
}
return((Cardinal) left);
}
/* ---------------------------------------------------------------------------
* returns a the minimum index which matches
* X(PV[index]) <= X for all index <= 'found one'
* the field is sorted in a ascending order
*/
static Cardinal GetPVByX(Position X)
{
int left = 0,
right = TotalPV -1,
position;
while (left < right)
{
position = (left +right) /2;
if (PVSortedByX[position].Data->X >= X)
right = position;
else
left = position+1;
}
return((Cardinal) left);
}
/* ---------------------------------------------------------------------------
* releases all allocated memory
*/
static void FreeConnectionLookupMemory(void)
{
Cardinal i;
for (i = 0; i < MAX_LAYER; i++)
{
MyFree((char **) &LineSortedByLowX[i]);
MyFree((char **) &LineSortedByHighX[i]);
MyFree((char **) &LineList[i].Data);
MyFree((char **) &PolygonList[i].Data);
}
MyFree((char **) &PVSortedByX);
MyFree((char **) &PVList.Data);
}
/* ---------------------------------------------------------------------------
* allocates memory for stacks ...
* initializes index and sorts it by X1 and X2
*/
static void InitConnectionLookup(void)
{
Cardinal i,
pos;
/* initialize line and polygon data */
for (i = 0; i < MAX_LAYER; i++)
{
LayerTypePtr layer = &PCB->Data->Layer[i];
if (layer->LineN)
{
/* allocate memory for line pointer lists */
LineSortedByLowX[i] = (LineTypePtr *) MyCalloc(layer->LineN,
sizeof(LineTypePtr), "InitConnectionLookup()");
LineSortedByHighX[i] = (LineTypePtr *) MyCalloc(layer->LineN,
sizeof(LineTypePtr), "InitConnectionLookup()");
LineList[i].Data = (void **) MyCalloc(layer->LineN,
sizeof(LineTypePtr), "InitConnectionLookup()");
/* copy addresses to arrays and sort them */
LINE_LOOP(layer,
LineSortedByLowX[i][n] = LineSortedByHighX[i][n] = line;
);
qsort(LineSortedByLowX[i], layer->LineN, sizeof(LineTypePtr),
CompareLineByLowX);
qsort(LineSortedByHighX[i], layer->LineN, sizeof(LineTypePtr),
CompareLineByHighX);
}
/* allocate memory for polygon list */
if (layer->PolygonN)
PolygonList[i].Data = (void **) MyCalloc(layer->PolygonN,
sizeof(PolygonTypePtr), "InitConnectionLookup()");
/* clear some struct members */
LineList[i].Position = 0;
LineList[i].DrawPosition = 0;
LineList[i].Number = 0;
PolygonList[i].Position = 0;
PolygonList[i].DrawPosition = 0;
PolygonList[i].Number = 0;
}
/* pin and via data; start with counting their total number,
* then allocate memory and copy the data to a tmp field
* set number of the according element in tmp field too
*/
TotalPV = PCB->Data->ViaN;
ELEMENT_LOOP(PCB->Data, TotalPV += element->PinN; );
PVSortedByX = (PVDataTypePtr) MyCalloc(TotalPV, sizeof(PVDataType),
"InitConnectionLookup()");
/* copy via data; field is initialized with NULL */
pos = 0;
VIA_LOOP(PCB->Data, PVSortedByX[pos++].Data = via; );
ELEMENT_LOOP(PCB->Data,
PIN_LOOP(element,
PVSortedByX[pos].Data = pin;
PVSortedByX[pos++].Element = element;
);
);
/* sort array by X */
qsort(PVSortedByX, TotalPV, sizeof(PVDataType), ComparePVByX);
/* allocate memory for 'new PV to check' list and clear struct */
PVList.Data = (void **) MyCalloc(TotalPV, sizeof(PVDataTypePtr),
"InitConnectionLookup()");
PVList.Position = 0;
PVList.DrawPosition = 0;
PVList.Number = 0;
}
/* ---------------------------------------------------------------------------
* returns a pointer into the sorted list with the highest index and the
* number of entries left to check
* All list entries starting from the pointer position to the end
* may match the specified x coordinate range.
*/
static LineTypePtr *GetIndexOfLines(Position Xlow, Position Xhigh,
Cardinal Layer, Cardinal *Number)
{
Cardinal index1,
index2;
/* get index of the first line that may match the coordinates
* see GetLineByLowX(), GetLineByHighX()
* take the field with less entries to speed up searching
*/
index1 = GetLineByLowX(Xhigh, Layer);
index2 = GetLineByHighX(Xlow, Layer);
if (index1 > index2)
{
*Number = PCB->Data->Layer[Layer].LineN -index1;
return(&LineSortedByLowX[Layer][index1]);
}
*Number = PCB->Data->Layer[Layer].LineN -index2;
return(&LineSortedByHighX[Layer][index2]);
}
/* ---------------------------------------------------------------------------
* finds a PV by it's coordinates in the sorted list
* A pointer to the list entry or NULL is returned
*/
static PVDataTypePtr LookupPVByCoordinates(Position X, Position Y)
{
Cardinal i, limit;
/* get absolute lower/upper boundary */
i = GetPVByX(X -MAX_PINORVIASIZE);
limit = GetPVByX(X +MAX_PINORVIASIZE +1);
while (i <= limit)
{
PinTypePtr ptr = PVSortedByX[i].Data;
/* check which one matches */
if (abs(ptr->X - X) <= ptr->Thickness/4 &&
abs(ptr->Y - Y) <= ptr->Thickness/4)
return(&PVSortedByX[i]);
i++;
}
return(NULL);
}
/* ---------------------------------------------------------------------------
* checks if a PV is connected to LOs, if it is, the LO is added to
* the appropriate list and the 'used' flag is set
*/
static void LookupLOConnectionsToPVList(void)
{
PinTypePtr pv;
Cardinal layer;
/* loop over all PVs currently on list */
while (PVList.Position < PVList.Number)
{
/* get pointer to data */
pv = PVLIST_ENTRY(PVList.Position)->Data;
for (layer = 0; layer < MAX_LAYER; layer++)
{
PolygonTypePtr polygon = PCB->Data->Layer[layer].Polygon;
Dimension distance = (MAX_LINESIZE + pv->Thickness) /3;
LineTypePtr *sortedptr;
Cardinal i;
/* get the lowest data pointer of lines which may have
* a connection to the PV ### line->X1 <= line->X2 ###
*/
sortedptr = GetIndexOfLines(pv->X -distance, pv->X +distance,
layer, &i);
for (; i; i--, sortedptr++)
if (!TEST_FLAG(FOUNDFLAG, *sortedptr) &&
IS_PV_ON_LINE(pv, *sortedptr))
ADD_LINE_TO_LIST(layer, *sortedptr);
/* check all polygons */
for (i = 0; i < PCB->Data->Layer[layer].PolygonN; i++, polygon++)
if (!TEST_FLAG(FOUNDFLAG, polygon) &&
IsPointInPolygon(polygon, pv->X, pv->Y))
ADD_POLYGON_TO_LIST(layer, polygon);
}
PVList.Position++;
}
}
/* ---------------------------------------------------------------------------
* find all connections between LO at the current list position and new LOs
*/
static void LookupLOConnectionsToLOList(void)
{
Cardinal i,
group;
Cardinal lineposition[MAX_LAYER],
polyposition[MAX_LAYER];
/* copy the current LO list positions; the original data is changed
* by 'LookupPVConnectionsToLOList()' which has to check the same
* list entries plus the new ones
*/
for (i = 0; i< MAX_LAYER; i++)
{
lineposition[i] = LineList[i].Position;
polyposition[i] = PolygonList[i].Position;
}
/* loop over all layergroups */
for (group = 0; group < MAX_LAYER; group++)
{
Cardinal entry;
Boolean done;
/* loop over all new LOs in the list;
* recurse till no more new connections n the layergroup were found
*/
do
{
for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
{
Cardinal layer = PCB->LayerGroups.Entries[group][entry];
Cardinal *position;
/* try all new lines */
position = &lineposition[layer];
for (; *position < LineList[layer].Number; (*position)++)
LookupLOConnectionsToLine(
LINELIST_ENTRY(layer, *position), group);
/* try all new polygons */
position = &polyposition[layer];
for (; *position < PolygonList[layer].Number; (*position)++)
LookupLOConnectionsToPolygon(
POLYGONLIST_ENTRY(layer, *position), group);
}
/* check if both lists are handled, the second for-loop may
* have changed the line list
*/
done = True;
for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++)
{
Cardinal layer = PCB->LayerGroups.Entries[group][entry];
done = done &&
lineposition[layer] >= LineList[layer].Number &&
polyposition[layer] >= PolygonList[layer].Number;
}
} while (!done);
}
}
/* ---------------------------------------------------------------------------
* searches for new PVs that are connected to NEW LOs on the list
* This routine updates the position counter of the lists too.
*/
static void LookupPVConnectionsToLOList(void)
{
Cardinal layer,
i,
limit;
Dimension distance;
/* loop over all layers */
for (layer = 0; layer < MAX_LAYER; layer++)
{
/* check all lines */
while (LineList[layer].Position < LineList[layer].Number)
{
LineTypePtr line = LINELIST_ENTRY(layer, LineList[layer].Position);
/* get the positions in sorted field to speed up searching
* ### line->X1 <= line->X2 ###
* the '+1' in the second call of GetPVByX()
* makes sure that 'limit' is realy the position outside the
* range
*/
distance = (MAX_PINORVIASIZE +line->Thickness) /3;
i = GetPVByX(line->X1 -distance);
limit = GetPVByX(line->X2 +distance +1);
for (; i <= limit; i++)
{
PinTypePtr pv = PVSortedByX[i].Data;
if (!TEST_FLAG(FOUNDFLAG, pv) && IS_PV_ON_LINE(pv, line))
ADD_PV_TO_LIST(&PVSortedByX[i]);
}
LineList[layer].Position++;
}
/* now all polygons */
while (PolygonList[layer].Position < PolygonList[layer].Number)
{
PolygonTypePtr polygon;
polygon = POLYGONLIST_ENTRY(layer, PolygonList[layer].Position);
/* get the positions in sorted field to speed up searching */
distance = MAX_PINORVIASIZE /3;
i = GetPVByX(polygon->BoundingBox.X1 -distance);
limit = GetPVByX(polygon->BoundingBox.X2 +distance +1);
for (; i <= limit; i++)
{
PinTypePtr pv = PVSortedByX[i].Data;
if (!TEST_FLAG(FOUNDFLAG, pv) &&
IsPointInPolygon(polygon, pv->X, pv->Y))
ADD_PV_TO_LIST(&PVSortedByX[i]);
}
PolygonList[layer].Position++;
}
}
}
/* ---------------------------------------------------------------------------
* checks if two lines intersect
* constant recognition by the optimizer is assumed
* from news FAQ:
*
* Let A,B,C,D be 2-space position vectors. Then the directed line
* segments AB & CD are given by:
*
* AB=A+r(B-A), r in [0,1]
* CD=C+s(D-C), s in [0,1]
*
* If AB & CD intersect, then
*
* A+r(B-A)=C+s(D-C), or
*
* XA+r(XB-XA)=XC+s(XD-XC)
* YA+r(YB-YA)=YC+s(YD-YC) for some r,s in [0,1]
*
* Solving the above for r and s yields
*
* (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
* r = ----------------------------- (eqn 1)
* (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
*
* (YA-YC)(XB-XA)-(XA-XC)(YB-YA)
* s = ----------------------------- (eqn 2)
* (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
*
* Let I be the position vector of the intersection point, then
*
* I=A+r(B-A) or
*
* XI=XA+r(XB-XA)
* YI=YA+r(YB-YA)
*
* By examining the values of r & s, you can also determine some
* other limiting conditions:
*
* If 0<=r<=1 & 0<=s<=1, intersection exists
* r<0 or r>1 or s<0 or s>1 line segments do not intersect
*
* If the denominator in eqn 1 is zero, AB & CD are parallel
* If the numerator in eqn 1 is also zero, AB & CD are coincident
*
* If the intersection point of the 2 lines are needed (lines in this
* context mean infinite lines) regardless whether the two line
* segments intersect, then
*
* If r>1, I is located on extension of AB
* If r<0, I is located on extension of BA
* If s>1, I is located on extension of CD
* If s<0, I is located on extension of DC
*
* Also note that the denominators of eqn 1 & 2 are identical.
*
*
*
*
*
*/
static Boolean LineLineIntersect(LineTypePtr Line1, LineTypePtr Line2)
{
float r, s,
denum,
radius,
dx, dy;
denum = (float) (Line1->X2 -Line1->X1)*(float) (Line2->Y2 -Line2->Y1) -
(float) (Line1->Y2 -Line1->Y1)*(float) (Line2->X2 -Line2->X1);
/* handle parallel lines */
if (denum == 0.0)
{
/* at least one of the two end points of one segment
* has to have a minimum distance to the other segment
*/
return(
IsPointOnLine(Line1->X1, Line1->Y1, Line1->Thickness/2.0, Line2) ||
IsPointOnLine(Line1->X2, Line1->Y2, Line1->Thickness/2.0, Line2) ||
IsPointOnLine(Line2->X1, Line2->Y1, Line2->Thickness/2.0, Line1) ||
IsPointOnLine(Line2->X2, Line2->Y2, Line2->Thickness/2.0, Line1));
}
r = (float) (Line1->Y1 -Line2->Y1)*(float) (Line2->X2 -Line2->X1) -
(float) (Line1->X1 -Line2->X1)*(float) (Line2->Y2 -Line2->Y1);
r /= denum;
s = (float) (Line1->Y1 -Line2->Y1)*(float) (Line1->X2 -Line1->X1) -
(float) (Line1->X1 -Line2->X1)*(float) (Line1->Y2 -Line1->Y1);
s /= denum;
/* intersection is at least on AB */
if (r >= 0.0 && r <= 1.0)
{
if (s >= 0.0 && s <= 1.0)
return(True);
/* intersection on AB and extension of CD */
return(s < 0.0 ?
IsPointOnLine(Line2->X1, Line2->Y1, Line2->Thickness/2.0, Line1) :
IsPointOnLine(Line2->X2, Line2->Y2, Line2->Thickness/2.0, Line1));
}
/* intersection is on least on CD */
if (s >= 0.0 && s <= 1.0)
{
/* intersection on CD and extension of AB */
return(r < 0.0 ?
IsPointOnLine(Line1->X1, Line1->Y1, Line1->Thickness/2.0, Line2) :
IsPointOnLine(Line1->X2, Line1->Y2, Line1->Thickness/2.0, Line2));
}
/* no intersection of zero-width lines but maybe of thick lines;
* we just have two check the distance of the endpoint of the two
* segments which are next to the intersection point
*/
radius = (float) (Line1->Thickness +Line2->Thickness)/2.0 +1.0;
radius *= radius;
if (s < 0.0)
{
dx = (float) ((r < 0.0 ? Line1->X1 : Line1->X2) -Line2->X1);
dy = (float) ((r < 0.0 ? Line1->Y1 : Line1->Y2) -Line2->Y1);
return(dx*dx +dy*dy <= radius);
}
dx = (float) ((r < 0.0 ? Line1->X1 : Line1->X2) -Line2->X2);
dy = (float) ((r < 0.0 ? Line1->Y1 : Line1->Y2) -Line2->Y2);
return(dx*dx +dy*dy <= radius);
}
/* ---------------------------------------------------------------------------
* searches all LOs that are connected to the given line on the given
* layergroup. All found connections are added to the list
*
* the notation that is used is:
* Xij means Xj at line i
*/
static void LookupLOConnectionsToLine(LineTypePtr Line, Cardinal LayerGroup)
{
Cardinal entry;
Dimension distance;
/* the maximum possible distance */
distance = (Line->Thickness +MAX_LINESIZE) /2;
/* loop over all layers of the group */
for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
{
PolygonTypePtr polygon;
LineTypePtr *sortedptr;
Cardinal layer,
i;
/* get index of the first line that may match the coordinates */
layer = PCB->LayerGroups.Entries[LayerGroup][entry];
sortedptr = GetIndexOfLines(Line->X1 -distance, Line->X2 +distance,
layer, &i);
/* loop till the end of the data is reached
* DONT RETRY LINES THAT HAVE BEEN FOUND
*/
for (; i; i--, sortedptr++)
if (!TEST_FLAG(FOUNDFLAG, *sortedptr) &&
LineLineIntersect(Line, *sortedptr))
ADD_LINE_TO_LIST(layer, *sortedptr);
/* now check all polygons */
i = 0;
polygon = PCB->Data->Layer[layer].Polygon;
for (; i < PCB->Data->Layer[layer].PolygonN; i++, polygon++)
if (!TEST_FLAG(FOUNDFLAG, polygon) &&
IsLineInPolygon(Line, polygon))
ADD_POLYGON_TO_LIST(layer, polygon);
}
}
/* ---------------------------------------------------------------------------
* looks up LOs that are connected to the given polygon
* on the given layergroup. All found connections are added to the list
*/
static void LookupLOConnectionsToPolygon(PolygonTypePtr Polygon,
Cardinal LayerGroup)
{
Cardinal entry;
/* loop over all layers of the group */
for (entry = 0; entry < PCB->LayerGroups.Number[LayerGroup]; entry++)
{
PolygonTypePtr polygon;
LineTypePtr *sortedptr;
Cardinal layer,
i;
layer = PCB->LayerGroups.Entries[LayerGroup][entry];
/* check all polygons */
polygon = PCB->Data->Layer[layer].Polygon;
for (i = 0; i < PCB->Data->Layer[layer].PolygonN; i++, polygon++)
if (!TEST_FLAG(FOUNDFLAG, polygon) &&
IsPolygonInPolygon(polygon, Polygon))
ADD_POLYGON_TO_LIST(layer, polygon);
/* and now check all lines, first reduce the number of lines by
* evaluating the coordinates from the sorted lists
*/
sortedptr = GetIndexOfLines(Polygon->BoundingBox.X1 -MAX_LINESIZE/2,
Polygon->BoundingBox.X2 +MAX_LINESIZE/2, layer, &i);
/* now check all lines that match the condition */
for (; i; i--, sortedptr++)
if (!TEST_FLAG(FOUNDFLAG, *sortedptr) &&
IsLineInPolygon(*sortedptr, Polygon))
ADD_LINE_TO_LIST(layer, *sortedptr);
}
}
/* ---------------------------------------------------------------------------
* checks if a line has a connection to a polygon
*
* - first check if the line can intersect with the polygon by
* evaluating the bounding boxes
* - check the two end points of the line. If none of them matches
* - check all segments of the polygon agains the line.
*/
static Boolean IsLineInPolygon(LineTypePtr Line, PolygonTypePtr Polygon)
{
if (MIN(Line->X1, Line->X2) <= Polygon->BoundingBox.X2 &&
MIN(Line->Y1, Line->Y2) <= Polygon->BoundingBox.Y2 &&
MAX(Line->X1, Line->X2) >= Polygon->BoundingBox.X1 &&
MAX(Line->Y1, Line->Y2) >= Polygon->BoundingBox.Y1)
{
LineType line;
if (IsPointInPolygon(Polygon, Line->X1, Line->Y1) ||
IsPointInPolygon(Polygon, Line->X2, Line->Y2))
return(True);
/* check all lines, start with the connection of the first-last
* polygon point; POLYGONPOINT_LOOP decrements the pointers !!!
*/
line.X1 = Polygon->Points[0].X;
line.Y1 = Polygon->Points[0].Y;
line.Thickness = 0;
POLYGONPOINT_LOOP(Polygon,
line.X2 = point->X;
line.Y2 = point->Y;
if (LineLineIntersect(Line, &line))
return(True);
line.X1 = line.X2;
line.Y1 = line.Y2;
);
}
return(False);
}
/* ---------------------------------------------------------------------------
* checks if a polygon has a connection to a second one
*
* First check all points out of P1 against P2 and vice versa.
* If both fail check all lines of P1 agains the ones of P2
*/
static Boolean IsPolygonInPolygon(PolygonTypePtr P1, PolygonTypePtr P2)
{
/* first check if both bounding boxes intersect */
if (P1->BoundingBox.X1 <= P2->BoundingBox.X2 &&
P1->BoundingBox.X2 >= P2->BoundingBox.X1 &&
P1->BoundingBox.Y1 <= P2->BoundingBox.Y2 &&
P1->BoundingBox.Y2 >= P2->BoundingBox.Y1)
{
LineType line;
POLYGONPOINT_LOOP(P1,
if (IsPointInPolygon(P2, point->X, point->Y))
return(True);
);
POLYGONPOINT_LOOP(P2,
if (IsPointInPolygon(P1, point->X, point->Y))
return(True);
);
/* check all lines of P1 agains P2;
* POLYGONPOINT_LOOP decrements the pointer !!!
*/
line.X1 = P1->Points[0].X;
line.Y1 = P1->Points[1].Y;
line.Thickness = 0;
POLYGONPOINT_LOOP(P1,
line.X2 = point->X;
line.Y2 = point->Y;
if (IsLineInPolygon(&line, P2))
return(True);
line.X1 = line.X2;
line.Y1 = line.Y2;
);
}
return(False);
}
/* ---------------------------------------------------------------------------
* prints all found connections of a pin to file FP
* the connections are stacked in 'PVList'
*/
static void PrintPinConnections(FILE *FP)
{
Cardinal i,
indent,
linelength;
PVDataTypePtr pv;
char *ename,
*pname;
size_t len;
/* the staring pin */
pv = PVLIST_ENTRY(0);
pname = UNKNOWN(pv->Data->Name);
fprintf(FP, " %s: ", pname);
linelength = indent = strlen(pname) +4;
/* start with 'i' == 1 because entry[0] is the starting pin itself */
for (i = 1; i < PVList.Number; i++)
{
pv = PVLIST_ENTRY(i);
pname = EMPTY(pv->Data->Name);
/* get the elements name or assume that its a via */
ename = pv->Element ? UNKNOWN(ELEMENT_NAME(PCB, pv->Element)) : "via";
/* new line ? */
len = 4 +strlen(pname) +strlen(ename);
linelength += len;
if (linelength >= Settings.CharPerLine)
{
linelength = indent +len;
fprintf(FP, "\n%*s%s(%s), ", (int) indent, "", pname, ename);
}
else
fprintf(FP, "%s(%s), ", pname, ename);
}
/* there might be only one pin in list --> no connections */
if (PVList.Number == 1)
fputs("no connection", FP);
fputc('\n', FP);
}
/* ---------------------------------------------------------------------------
* checks if all lists of new objects are handled
*/
static Boolean ListsEmpty(void)
{
Boolean empty;
int i;
empty = (PVList.Position >= PVList.Number);
for (i = 0; i < MAX_LAYER && empty; i++)
empty = empty &&
LineList[i].Position >= LineList[i].Number &&
PolygonList[i].Position >= PolygonList[i].Number;
return(empty);
}
/* ---------------------------------------------------------------------------
* loops till no more connections are found
*/
static void DoIt(void)
{
do
{
/* lookup connections; these are the steps (2) to (4)
* from the description
*/
LookupLOConnectionsToPVList();
LookupLOConnectionsToLOList();
LookupPVConnectionsToLOList();
DrawNewConnections();
} while (!ListsEmpty());
}
/* ---------------------------------------------------------------------------
* prints all unused pins of an element to file FP
*/
static Boolean PrintAndSelectUnusedPinsOfElement(ElementTypePtr Element,
FILE *FP)
{
size_t indent = 0, /* init to get rid of compiler warning */
linelength = 0;
Boolean first = True;
/* check all pins in element */
PIN_LOOP(Element,
{
PVDataTypePtr entry;
/* lookup pin in list */
entry = LookupPVByCoordinates(pin->X, pin->Y);
/* pin might has bee checked before, add to list if not */
if (!TEST_FLAG(FOUNDFLAG, entry->Data) && FP)
{
Cardinal layer;
ADD_PV_TO_LIST(entry);
DoIt();
/* the pin has no connection if it's the
* only list entry
*/
if (PVList.Number == 1)
{
char *pname = EMPTY(entry->Data->Name);
size_t len = strlen(pname) +2;
/* output of element name if not already done */
if (first)
{
fprintf(FP, "%s(%s): ",UNKNOWN(CANONICAL_NAME(Element)),
UNKNOWN(NAMEONPCB_NAME(Element)));
indent = strlen(UNKNOWN(CANONICAL_NAME(Element))) +
strlen(UNKNOWN(NAMEONPCB_NAME(Element))) +4;
linelength = indent;
first = False;
}
/* new line ? */
linelength += len;
if (linelength >= Settings.CharPerLine)
{
linelength = indent +len;
fprintf(FP, "\n%*s%s, ", (int) indent, "", pname);
}
else
fprintf(FP, "%s, ", pname);
/* select object */
SET_FLAG(SELECTEDFLAG, entry->Data);
DrawPin(entry->Data);
}
/* reset found LOs for the next pin */
for (layer = 0; layer < MAX_LAYER; layer++)
{
LineList[layer].Position = LineList[layer].Number = 0;
PolygonList[layer].Position = PolygonList[layer].Number = 0;
}
PVList.Number = PVList.Position = 0;
if (CheckAbort())
{
fputs("\n\nABORTED...\n", FP);
return(True);
}
}
}
);
/* print seperator if element has unused pins */
if (!first)
{
fputc('\n', FP);
SEPERATE(FP);
}
return(False);
}
/* ---------------------------------------------------------------------------
* finds all connections to the pins of the passed element.
* The result is written to filedescriptor 'FP'
* Returns True if operation was aborted
*/
static Boolean PrintElementConnections(ElementTypePtr Element,
FILE *FP)
{
Cardinal layer;
fprintf(FP, "%s(%s)\n", UNKNOWN(CANONICAL_NAME(Element)),
UNKNOWN(NAMEONPCB_NAME(Element)));
/* check all pins in element */
PIN_LOOP(Element,
{
PVDataTypePtr entry;
/* lookup pin in list */
entry = LookupPVByCoordinates(pin->X, pin->Y);
/* pin might has bee checked before, add to list if not */
if (TEST_FLAG(FOUNDFLAG, entry->Data) && FP)
{
fprintf(FP, " %s: has been checked before\n",
UNKNOWN(pin->Name));
continue;
}
ADD_PV_TO_LIST(entry);
DoIt();
/* printout all found connections */
PrintPinConnections(FP);
/* reset found LOs for the next pin */
for (layer = 0; layer < MAX_LAYER; layer++)
{
LineList[layer].Position = LineList[layer].Number = 0;
PolygonList[layer].Position = PolygonList[layer].Number = 0;
}
PVList.Number = PVList.Position = 0;
if (CheckAbort())
{
fputs("\n\nABORTED...\n", FP);
return(True);
}
}
);
return(False);
}
/* ---------------------------------------------------------------------------
* draws all new connections which have been found since the
* routine was called the last time
*/
static void DrawNewConnections(void)
{
int i;
/* decrement 'i' to keep layerstack order */
for (i = MAX_LAYER-1; i != -1; i--)
{
Cardinal layer = LayerStack[i],
position;
if (PCB->Data->Layer[layer].On)
{
/* draw all new lines */
position = LineList[layer].DrawPosition;
for (; position < LineList[layer].Number; position++)
DrawLine(&PCB->Data->Layer[layer],
LINELIST_ENTRY(layer, position));
LineList[layer].DrawPosition = LineList[layer].Number;
/* draw all new polygons */
position = PolygonList[layer].DrawPosition;
for (; position < PolygonList[layer].Number; position++)
DrawPolygon(&PCB->Data->Layer[layer],
POLYGONLIST_ENTRY(layer, position));
PolygonList[layer].DrawPosition = PolygonList[layer].Number;
}
}
/* draw all new PVs; 'PVList' holds an array of pointers to the
* array of sorted pointers to PV data
*/
while (PVList.DrawPosition < PVList.Number)
{
PVDataTypePtr pv = PVLIST_ENTRY(PVList.DrawPosition);
if (TEST_FLAG(PINFLAG, pv->Data))
{
if (PCB->PinOn)
DrawPin(pv->Data);
}
else
if (PCB->ViaOn)
DrawVia(pv->Data);
PVList.DrawPosition++;
}
}
/* ---------------------------------------------------------------------------
* find all connections to pins within one element
*/
void LookupElementConnections(ElementTypePtr Element, FILE *FP)
{
/* reset all currently marked connections */
CreateAbortDialog();
ResetConnections();
InitConnectionLookup();
PrintElementConnections(Element, FP);
SetChangedFlag(True);
EndDialog(Popup);
if (Settings.RingBellWhenFinished)
XBell(Dpy, Settings.Volume);
FreeConnectionLookupMemory();
RedrawOutput();
}
/* ---------------------------------------------------------------------------
* find all connections to pins of all element
*/
void LookupConnectionsToAllElements(FILE *FP)
{
/* reset all currently marked connections */
CreateAbortDialog();
ResetConnections();
InitConnectionLookup();
ELEMENT_LOOP(PCB->Data,
/* break if abort dialog returned True */
if (PrintElementConnections(element, FP))
break;
SEPERATE(FP);
if (Settings.ResetAfterElement && n != 1)
ResetConnections();
);
EndDialog(Popup);
if (Settings.RingBellWhenFinished)
XBell(Dpy, Settings.Volume);
FreeConnectionLookupMemory();
RedrawOutput();
}
/* ---------------------------------------------------------------------------
* looks up all connections from the object at the given coordinates
* the 'FOUNDFLAG' is set for all objects found
*/
void LookupConnection(Position X, Position Y)
{
void *ptr1, *ptr2;
int type;
/* check if there are any pins or vias at that position */
type = SearchObjectByPosition(LOOKUP_TYPES, &ptr1, &ptr2, X, Y);
if (type == NO_TYPE)
return;
InitConnectionLookup();
/* now add the object to the appropriate list and start scanning
* This is step (1) from the description
*/
switch(type)
{
case PIN_TYPE:
case VIA_TYPE:
{
PVDataTypePtr entry;
entry = LookupPVByCoordinates(X, Y);
ADD_PV_TO_LIST(entry);
break;
}
case LINE_TYPE:
{
int layer = GetLayerNumber(PCB->Data, (LayerTypePtr) ptr1);
ADD_LINE_TO_LIST(layer, (LineTypePtr) ptr2);
break;
}
case POLYGON_TYPE:
{
int layer = GetLayerNumber(PCB->Data, (LayerTypePtr) ptr1);
ADD_POLYGON_TO_LIST(layer, (PolygonTypePtr) ptr2);
break;
}
default:
return;
}
DoIt();
/* we are done */
if (Settings.RingBellWhenFinished)
XBell(Dpy, Settings.Volume);
FreeConnectionLookupMemory();
}
/* ---------------------------------------------------------------------------
* find all unused pins of all element
*/
void LookupUnusedPins(FILE *FP)
{
/* reset all currently marked connections */
CreateAbortDialog();
ResetConnections();
InitConnectionLookup();
ELEMENT_LOOP(PCB->Data,
/* break if abort dialog returned True;
* passing NULL as filedescriptor discards the normal output
*/
if (PrintAndSelectUnusedPinsOfElement(element, FP))
break;
);
EndDialog(Popup);
ResetConnections();
if (Settings.RingBellWhenFinished)
XBell(Dpy, Settings.Volume);
FreeConnectionLookupMemory();
RedrawOutput();
}
/* ---------------------------------------------------------------------------
* resets all used flags of pins and vias
*/
void ResetFoundPinsAndVias(void)
{
VIA_LOOP(PCB->Data, CLEAR_FLAG(FOUNDFLAG, via); );
ELEMENT_LOOP(PCB->Data,
PIN_LOOP(element, CLEAR_FLAG(FOUNDFLAG, pin); );
);
SetChangedFlag(True);
}
/* ---------------------------------------------------------------------------
* resets all used flags of LOs
*/
void ResetFoundLinesAndPolygons(void)
{
ALLLINE_LOOP(PCB->Data, CLEAR_FLAG(FOUNDFLAG, line); );
ALLPOLYGON_LOOP(PCB->Data, CLEAR_FLAG(FOUNDFLAG, polygon); );
SetChangedFlag(True);
}
/* ---------------------------------------------------------------------------
* resets all found connections
*/
static void ResetConnections(void)
{
ResetFoundPinsAndVias();
ResetFoundLinesAndPolygons();
RedrawOutput();
}